import base64
import json
import pickle

from django import http
from django.shortcuts import render
from django.views import View
from django_redis import get_redis_connection

from carts.utils import merge_carts
from goods.models import SKU
from utils.response_code import RET


class CartsView(View):
    def post(self, request):
        # 处理添加购物车请求,   接受登录用户, 或非登录用户访问
        # 1, 初始化数据
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)  # True,  False

        if not all([sku_id, count]):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '参数不全'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '商品标号有误'})

        try:
            count = int(count)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '数量有误'})

        if not isinstance(selected, bool):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '选择状态有误'})

        # 2, 处理业务逻辑
        user = request.user
        # 判断用户的状态
        if user.is_authenticated:
            # 2,1 用户登录状态,
            # redis
            # hash carts_userid:{sku_id:count}
            # set selected_userid: {sku_id, sku_id2}

            redis_conn = get_redis_connection('carts')
            cart_dict = redis_conn.hgetall('carts_%s' % user.id)  # {sku_id:5}
            if str(sku_id).encode() in cart_dict:
                # 如果原来的购物车中已经存在这个商品, 就将数量加上原来购物车中的数量
                count += int(cart_dict[str(sku_id).encode()])

            redis_conn.hset('carts_%s' % user.id, sku.id, count)
            if selected:
                redis_conn.sadd('selected_%s' % user.id, sku.id)
            else:
                redis_conn.srem('selected_%s' % user.id, sku.id)

            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            return http.JsonResponse(res)

            pass
        else:
            # 2,2 匿名用户
            # 保存在cookie中
            # {
            #     "sku_id1":{
            #         "count":"1",
            #         "selected":"True"
            #     },
            # }
            # 取一下已经存在的购物车
            cart_base64 = request.COOKIES.get('carts')

            if cart_base64:
                cart_dict = pickle.loads(base64.b64decode(cart_base64))
            else:
                cart_dict = {}

            # 判断一下添加的商品是否已经在购物车, 已经在购物车, 就累加数量
            if sku_id in cart_dict:
                count += int(cart_dict[sku_id]["count"])

            # 构建数据结构
            cart_dict[sku.id] = {'count': count, 'selected': selected}
            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            response = http.JsonResponse(res)

            # 转换成 base64
            d_base64 = base64.b64encode(pickle.dumps(cart_dict))
            # 保存在cookie中
            response.set_cookie('carts', d_base64)
            return response

            pass

        # 3, 返回响应
        pass

    def get(self, request):
        # 展示购物车页面
        # 1, 初始化数据
        user = request.user

        # 2, 处理业务逻辑
        if user.is_authenticated:
            # 登录用户
            # 增加合并购物车逻辑
            # 1, 如果cookie中有购物车数据, 就把cookie的购物合并到redis中
            # 1,1 获取cookie的购物车
            # 1, redis对象
            redis_conn = get_redis_connection('carts')
            carts_base64 = request.COOKIES.get('carts')

            # 1,2 解码购物车
            if carts_base64:
                carts_dict = pickle.loads(base64.b64decode(carts_base64))
                # {sku_id:{"count":1, "selected":True}}
            else:
                carts_dict = {}
            # 1,3 合并
            for sku_id, count_selected in carts_dict.items():
                redis_conn.hset('carts_%s' % user.id, sku_id, count_selected['count'])
                if count_selected['selected']:
                    redis_conn.sadd('selected_%s' % user.id, sku_id)
                else:
                    redis_conn.srem('selected_%s' % user.id, sku_id)

            # 2, 获取redis中的skuid
            carts_dict = redis_conn.hgetall('carts_%s' % user.id)
            # {sku_id:5}
            selected_list = redis_conn.smembers('selected_%s' % user.id)
            # [sku_id]

            # 3, 根据skuid组装需要的数据
            skus = []
            for sku_id in carts_dict:
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    "id": sku.id,
                    "selected": str(sku_id in selected_list),  # True , False
                    "default_image_url": sku.default_image_url.url,
                    "name": sku.name,
                    "price": str(sku.price),
                    "count": int(carts_dict[sku_id]),
                    "amount": str(sku.price * int(carts_dict[sku_id])),
                }
                skus.append(sku_data)

            context = {
                "cart_skus": json.dumps(skus)
            }

            response = render(request, 'cart.html', context=context)
            response.delete_cookie('carts')
            return response
            pass
        else:
            # 非登录用户
            # 1, 获取cookie的数据
            cart_base64 = request.COOKIES.get('carts')

            # 2, cookie数据转换成字典
            if cart_base64:
                cart_dict = pickle.loads(base64.b64decode(cart_base64))
            else:
                cart_dict = {}
            # {
            #     "sku_id1":{
            #         "count":"1",
            #         "selected":"True"
            #     },
            # }

            # 3, 组装数据
            skus = []
            for sku_id, count_selected in cart_dict.items():
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    "id": sku.id,
                    "selected": str(count_selected['selected']),  # True , False
                    "default_image_url": sku.default_image_url.url,
                    "name": sku.name,
                    "price": str(sku.price),
                    "count": int(count_selected['count']),
                    "amount": str(sku.price * int(count_selected['count'])),
                }
                skus.append(sku_data)

            # 4, 渲染模板
            context = {
                "cart_skus": json.dumps(skus)
            }
            return render(request, 'cart.html', context=context)
            pass

        # 3, 返回响应
        return render(request, 'cart.html')
        pass

    def put(self, request):
        # 修改购物车
        # 1, 初始化数据
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        count = data.get('count')
        selected = data.get('selected', True)

        if not all([sku_id, count]):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '参数不全'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '商品标号有误'})

        try:
            count = int(count)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '数量有误'})

        if not isinstance(selected, bool):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '选择状态有误'})

        # 2, 处理业务逻辑
        if user.is_authenticated:
            # 登录状态
            redis_conn = get_redis_connection('carts')
            # carts_dict = redis_conn.hgetall('carts_%s' % user.id)
            # selected_list = redis_conn.smembers('selected_%s' % user.id)

            redis_conn.hset('carts_%s' % user.id, sku_id, count)
            if selected:
                redis_conn.sadd('selected_%s' % user.id, sku_id)
            else:
                redis_conn.srem('selected_%s' % user.id, sku_id)
            sku_data = {
                'sku_id': sku_id,
                'count': count,
                'selected': selected
            }
            res = {
                'code': RET.OK,
                'errmsg': '成功',
                'cart_sku': sku_data
            }
            return http.JsonResponse(res)
            pass
        else:
            # 非登录状态
            #
            # 1, 先获取cookie中数据
            cart_base64 = request.COOKIES.get('carts')
            # 2, 解码cookie
            if cart_base64:
                cart_dict = pickle.loads(base64.b64decode(cart_base64))
            else:
                cart_dict = {}
            # 2, 直接覆盖cookie中相关产品的数据
            cart_dict[sku_id] = {'count': count, 'selected': selected}

            # 3, 编码, 设置cookie
            cart_base64 = base64.b64encode(pickle.dumps(cart_dict))

            # 4, 构造结果
            sku_data = {
                'sku_id': sku_id,
                'count': count,
                'selected': selected
            }
            res = {
                'code': RET.OK,
                'errmsg': '成功',
                'cart_sku': sku_data
            }
            response = http.JsonResponse(res)
            response.set_cookie('carts', cart_base64)
            return response
            pass

        # 3, 返回响应
        pass

    def delete(self, request):
        # 删除购物车商品
        # 1, 初始化数据
        user = request.user
        data = json.loads(request.body.decode())
        sku_id = data.get('sku_id')
        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception as e:
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '商品编号有误'})

        # 2, 处理业务逻辑
        if user.is_authenticated:
            # 登录用户
            redis_conn = get_redis_connection('carts')

            redis_conn.hdel('carts_%s' % user.id, sku_id)
            redis_conn.srem('selected_%s' % user.id, sku_id)

            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            return http.JsonResponse(res)
            pass
        else:
            # 非登录用户
            carts_base64 = request.COOKIES.get('carts')
            if carts_base64:
                carts_dict = pickle.loads(base64.b64decode(carts_base64))
            else:
                carts_dict = {}

            if sku_id in carts_dict:
                carts_dict.pop(sku_id)
            else:
                return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '购物车信息有误'})

            carts_base64 = base64.b64encode(pickle.dumps(carts_dict))

            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            response = http.JsonResponse(res)
            response.set_cookie('carts', carts_base64)

            return response

            pass

        # 3, 返回响应
        pass


class CartsSelectAllView(View):
    def put(self, request):
        # 处理用户的全选操作
        # 1, 初始化数据
        user = request.user
        data = json.loads(request.body.decode())
        selected = data.get('selected')

        if not isinstance(selected, bool):
            return http.JsonResponse({'code': RET.PARAMERR, 'errmsg': '选择状态有误'})

        # 2, 处理业务逻辑
        if user.is_authenticated:
            # 登录用户
            redis_conn = get_redis_connection('carts')
            carts_dict = redis_conn.hgetall('carts_%s' % user.id)  # {sku_id:3, sku_id2: 2}
            sku_ids = carts_dict.keys()  # 列表:  [sku_id, sku_id2]

            if selected:
                redis_conn.sadd('selected_%s' % user.id, *sku_ids)  # sku_ids -> sku_id, sku_id2
            else:
                redis_conn.srem('selected_%s' % user.id, *sku_ids)
            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            return http.JsonResponse(res)
        else:
            # 非登录用户
            # 获取cookie中的购物车信息
            carts_base64 = request.COOKIES.get('carts')

            # 解码购车信息
            if carts_base64:
                carts_dict = pickle.loads(base64.b64decode(carts_base64))
                # {sku_id:{'count':1,'selected': True},sku_id:{'count':1,'selected': True}}
            else:
                carts_dict = {}
            # 修改选择状态
            for sku_id, count_selected in carts_dict.items():
                count_selected['selected'] = selected
            # if selected:
            #     for sku_id, count_selected in carts_dict.items():
            #         count_selected['selected'] = True
            # else:
            #     for sku_id, count_selected in carts_dict.items():
            #         count_selected['selected'] = False
            # 编码购物车
            carts_base64 = base64.b64encode(pickle.dumps(carts_dict))
            res = {
                'code': RET.OK,
                'errmsg': '成功'
            }
            response = http.JsonResponse(res)
            response.set_cookie('carts', carts_base64)
            return response
            # 返回响应
            pass

        # 3, 返回响应
        pass


class CartsSimpleView(View):
    def get(self, request):
        # 获取简单购物车信息
        """
        {
            "code":"0",
            "errmsg":"OK",
            "cart_skus":[
                {
                    "id":1,
                    "name":"Apple MacBook Pro 13.3英寸笔记本 银色",
                    "count":1,
                    "default_image_url":"http://image.meiduo.site:8888/group1/M00/00/02/CtM3BVrPB4GAWkTlAAGuN6wB9fU4220429"
                },
                ......
            ]
        }
        :param request:
        :return:
        """
        # 1, 初始化数据
        user = request.user

        # 2, 处理业务逻辑
        if user.is_authenticated:
            # 登录状态

            # 调用合并购物车方法
            merge_carts(request)

            # 从redis中获取数据
            redis_conn = get_redis_connection('carts')
            carts_dict = redis_conn.hgetall('carts_%s' % user.id)  # 数据类型都是bytes

            # 组织数据
            """
            id	购物车SKU编号
            name	购物车SKU名称
            count	购物车SKU数量
            default_image_url	购物车SKU图片
            """
            skus = []
            for sku_id, count in carts_dict.items():
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    "id": sku.id,
                    "name": sku.name,
                    "count": int(count),  # bytes  ->  int
                    "default_image_url": sku.default_image_url.url,
                }
                skus.append(sku_data)

            # 返回响应
            res = {
                'code': RET.OK,
                'errmsg': '成功',
                'cart_skus': skus
            }
            return http.JsonResponse(res)
            pass
        else:
            # 非登录
            # 1, 取cookies中的购物车
            carts_base64 = request.COOKIES.get('carts')

            # 2,解码
            if carts_base64:
                carts_dict = pickle.loads(base64.b64decode(carts_base64))
            else:
                carts_dict = {}
            # 3,组织数据
            skus = []
            for sku_id, count_selected in carts_dict.items():
                sku = SKU.objects.get(id=sku_id)
                sku_data = {
                    "id": sku.id,
                    "name": sku.name,
                    "count": count_selected['count'],  # int
                    "default_image_url": sku.default_image_url.url,
                }
                skus.append(sku_data)

            # 4,返回数据
            res = {
                'code': RET.OK,
                'errmsg': '成功',
                'cart_skus': skus
            }
            return http.JsonResponse(res)
            pass

        # 3, 返回响应
        pass
